package com.fly.core;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.commons.dbutils.DbUtils;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * 数据源(jdbc-pool)管理工具
 * 
 * @author 00fly
 * @version [版本号, 2018-09-29]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class MySqlDBUtil
{
    private static final Logger LOGGER = LoggerFactory.getLogger(MySqlDBUtil.class);
    
    private static DataSource dataSource;
    
    // 使用ThreadLocal存储当前线程中的Connection对象
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    
    /**
     * <默认构造函数>
     */
    private MySqlDBUtil()
    {
        super();
    }
    
    // 静态初始化 DataSource
    static
    {
        ResourceBundle config = ResourceBundle.getBundle("jdbc");
        PoolProperties p = new PoolProperties();
        p.setUrl(config.getString("jdbc.url"));
        p.setDriverClassName(config.getString("jdbc.driver"));
        p.setUsername(config.getString("jdbc.username"));
        p.setPassword(config.getString("jdbc.password"));
        p.setFairQueue(true);// 异步获取连接,必须将fairQueue设置为true
        p.setJmxEnabled(true);
        p.setTestWhileIdle(false);
        p.setTestOnBorrow(true);
        p.setValidationQuery("SELECT 1");
        p.setTestOnReturn(false);
        p.setValidationInterval(30000);
        p.setTimeBetweenEvictionRunsMillis(30000);
        p.setMaxActive(100);
        p.setInitialSize(10);
        p.setMaxWait(10000);
        p.setRemoveAbandonedTimeout(60);
        p.setMinEvictableIdleTimeMillis(30000);
        p.setMinIdle(10);
        p.setLogAbandoned(true);
        p.setRemoveAbandoned(true);
        p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
        dataSource = new DataSource();
        dataSource.setPoolProperties(p);
    }
    
    /**
     * 获取数据库连接
     * 
     * @return
     * @throws SQLException
     * @throws ExecutionException
     * @throws InterruptedException
     * @see [类、类#方法、类#成员]
     */
    public static Connection getConnection()
        throws SQLException
    {
        try
        {
            Connection connection = threadLocal.get();
            if (connection == null)
            {
                Future<Connection> future = dataSource.getConnectionAsync();
                while (!future.isDone())
                {
                    try
                    {
                        TimeUnit.MICROSECONDS.sleep(100);
                    }
                    catch (InterruptedException iex)
                    {
                        Thread.currentThread().interrupt();
                        LOGGER.error(iex.getMessage(), iex);
                    }
                }
                connection = future.get();
                threadLocal.set(connection); // 把 connection绑定到当前线程上
            }
            return connection;
        }
        catch (Exception e)
        {
            LOGGER.error(e.getMessage(), e);
            throw new SQLException(e.getMessage(), e.getCause());
        }
    }
    
    /**
     * 释放数据库连接
     * 
     * @see [类、类#方法、类#成员]
     */
    public static void close(Connection connection)
    {
        // LOGGER.info("------释放资源: {}------", connection);
        DbUtils.closeQuietly(connection);
        threadLocal.remove(); // 解除当前线程上绑定conn
    }
    
    /**
     * 开启事务
     * 
     * @throws SQLException
     */
    public static void startTransaction()
        throws SQLException
    {
        Connection connection = threadLocal.get();
        if (connection == null)
        {
            connection = getConnection();
            connection.setAutoCommit(false); // 把事务提交方式改为手工提交
            threadLocal.set(connection); // 把 connection绑定到当前线程上
        }
        LOGGER.info("------开启事务: {}-------", connection);
    }
    
    /**
     * 提交事务并关闭连接
     * 
     * @throws SQLException
     * 
     */
    public static void commitAndClose()
        throws SQLException
    {
        Connection connection = threadLocal.get();
        LOGGER.info("------提交事务: {}-------", connection);
        try
        {
            connection.commit();
        }
        finally
        {
            connection.setAutoCommit(true);
            DbUtils.closeQuietly(connection);
            threadLocal.remove(); // 解除当前线程上绑定conn
        }
    }
    
    /**
     * 回滚事务并关闭连接
     * 
     * @throws SQLException
     * 
     */
    public static void rollbackAndClose()
        throws SQLException
    {
        Connection connection = threadLocal.get();
        LOGGER.info("------回滚事务: {}-------", connection);
        try
        {
            connection.rollback();
        }
        finally
        {
            connection.setAutoCommit(true);
            DbUtils.closeQuietly(connection);
            threadLocal.remove(); // 解除当前线程上绑定conn
        }
    }
}
